/*
 * License GNU LGPL
 * Copyright (C) 2012 Amrullah <amrullah@panemu.com>.
 */
package com.abc.cheque.ui.table;


import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType;
import javafx.scene.control.cell.PropertyValueFactory;

import com.abc.cheque.common.ExportToExcel;
import com.abc.cheque.common.TableCriteria;
import com.abc.cheque.common.TableData;
import com.abc.cheque.common.TiwulFXUtil;
import com.abc.cheque.ui.dialog.MessageDialog;
import com.abc.cheque.ui.dialog.MessageDialogBuilder;


/**
 * Controller for {@link TableControl}. The {@link #loadData(int, java.util.List, java.util.List, java.util.List, int)}
 * is mandatory to be implemented. That method should handle data population for 
 * {@link TableControl}
 * @author amrullah
 */
public abstract class TableController<T> {

    public abstract TableData loadData(int startIndex, List<TableCriteria> filteredColumns, List<String> sortedColumns, List<SortType> sortingOrders, int maxResult);

    /**
     * Override this method to implement insert routine. This method is called
     * when TableControl's save button is clicked.
     * @param newRecords
     * @return
     */
    public List<T> insert(List<T> newRecords) {
        throw new UnsupportedOperationException("Insert method is not supported");
    }

    /**
     * Override this method to implement update routine.
     * @param records
     * @return updated record list. If the record support optimistic locking the
     * version number should increase by 1
     */
    public List<T> update(List<T> records) {
        throw new UnsupportedOperationException("Update method is not supported");
    }

    /**
     * Override this method to implement delete routine.
     * @param records 
     */
    public void delete(List<T> records) {
        throw new UnsupportedOperationException("delete method is not supported");
    }

    /**
     * Called after user clicked insert button before a new row is added in the
     * table. To cancel insertion, return null. This method is useful for
     * setting default values to the new record.
     *
     * @param newRecord
     * @return null to cancel insertion
     */
    public T preInsert(T newRecord) {
        return newRecord;
    }

    /**
     * This method is called by {@link TableControl} when edit button is
     * clicked but before EDIT mode is actually activated. Override this method to
     * and return FALSE to cancel EDIT mode change.
     * @param selectedRecod
     * @return FALSE to cancel the EDIT mode. By default returns TRUE
     */
    public boolean canEdit(T selectedRecod) {
        return true;
    }

    /**
     * This method is called by {@link TableControl#delete()} before
     * it actually executes delete routine. If this methode returns FALSE,
     * the delete is cancelled.
     * @param table
     * @return 
     */
    public boolean canDelete(TableControl table) {
        MessageDialog.Answer answer = MessageDialogBuilder.confirmation()
                .message(TiwulFXUtil.getLiteral("msg.delete.confirmation"))
                .title(TiwulFXUtil.getLiteral("msg.delete.confirmation.title"))
                .defaultAnswer(MessageDialog.Answer.NO)
                .yesOkButtonText("Delete")
                .noButtonText("Don't Delete")
                .show(table.getScene().getWindow());
        return answer.equals(MessageDialog.Answer.YES_OK);
    }

    /**
     * Callback method to respond double click or ENTER on table's row
     * @param record 
     */
    public void doubleClick(T record) {
    }

    /**
     * Generic export to excel. This method is called by clicking TableControl's 
     * Export button. You can override this method to define title in the generated spreadsheet.
     * @param title
     * @param maxResult
     * @param tblView
     * @param lstCriteria 
     */
    public void exportToExcel(String title, int maxResult, TableControl<T> tblView, List<TableCriteria> lstCriteria) {
        try {
            ExportToExcel exporter = new ExportToExcel();
            List<Double> lstWidth = new ArrayList<>();
            BaseColumn baseColumn;
            List<T> data = new ArrayList<>();
            List<String> lstSortedColumn = new ArrayList<>();
            List<SortType> lstSortedType = new ArrayList<>();

            for (TableColumn<T, ?> tc : tblView.getTableView().getSortOrder()) {
                if (tc instanceof BaseColumn) {
                    lstSortedColumn.add(((BaseColumn) tc).getPropertyName());
                } else {
                    PropertyValueFactory valFactory = (PropertyValueFactory) tc.getCellValueFactory();
                    lstSortedColumn.add(valFactory.getProperty());
                }
                lstSortedType.add(tc.getSortType());
            }

            TableData vol;
            int startIndex2 = 0;

            do {
                vol = loadData(startIndex2, lstCriteria, lstSortedColumn, lstSortedType, maxResult);
                data.addAll((ObservableList<T>) FXCollections.observableArrayList(vol.getRows()));
                startIndex2 = startIndex2 + maxResult;
            } while (vol.isMoreRows());

            String tmpFolder = System.getProperty("java.io.tmpdir");
            File targetFile = File.createTempFile("test", ".xls", new File(tmpFolder));
          //  exporter.export(title, targetFile.getAbsolutePath(), tblView, data, lstWidth);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Callback method that is called after {@link #loadData(int, java.util.List, java.util.List, java.util.List, int) }
     */
    public void postLoadData() {
    }
    
    /**
     * Callback method that is called after {@link TableControl#save()  }.
     * @param previousMode Could be Mode.INSERT or Mode.EDIT
     */
    public void postSave(TableControl.Mode previousMode){}

    /**
     * Callback method designed to execute validation. This method is called
     * before {@link #update} and {@link #insert}
     *
     * @param changedRecords
     * @return
     */
    public boolean validate(List<T> changedRecords) {
        return true;
    }
}
